#include "ctcpconnect_v2.h"
#include <QThread>
#include "cmd_parse/cmd.h"
#include "serversetting.h"
#include "module/const_define.h"
#include "module/cnetworkthread.h"

static int g_connect_fail_times = 0;
static QString ip_update = "http://120.24.229.221:9999/";

CTcpConnect_v2::CTcpConnect_v2(QObject *parent) : QObject(parent)
{
    isSetUpPorject = false;
    _tcpSocket = NULL;
    _pushSocket = NULL;

    _updateMode = MODE_UPDATE_NONE;

    _need_update_all = false;
    _index_all_map = 0;

    _hostServer = QHostAddress("119.23.27.49");
    _hostPort = 9010;
    _udpUpdate.bind();

    connect(&_cmdParse,SIGNAL(s_deviceJsonReport(QString,QString)),
            this,SLOT(doGatewayDeviceStatusUpdate(QString,QString)));

    connect(&_cmdParse,SIGNAL(s_updateMode(QString)),this,SLOT(doChangeUpdateMode(QString)));
    connect(&_cmdParse,SIGNAL(s_controlCmd(QString)),this,SLOT(doControlCmd(QString)));


    _aliveTimer.setInterval(10000);//MSEC_STATE_CHECK);
    connect(&_aliveTimer,SIGNAL(timeout()),this,SLOT(doStateCheck()));
    _aliveTimer.start();

    _http = new CHttpManger(this);
    connect(_http,SIGNAL(s_reply(QByteArray)),this,SLOT(doReadProjectSetting(QByteArray)));

    connect(&_cmdParse,SIGNAL(s_updateMode(QString)),this,SLOT(doChangeUpdateMode(QString)));

    _deviceUpdateTimer.setInterval(500);
    connect(&_deviceUpdateTimer,SIGNAL(timeout()),this,SLOT(doUpdateDeviceStatus()));
    _deviceUpdateTimer.start();
}

void CTcpConnect_v2::doConnectToServer()
{
    qDebug() <<" v2 doConnectToServer";

    if(_tcpSocket)
    {
        delete _tcpSocket;
    }

    _tcpSocket = new CSyncTcpSocket();
    _tcpSocket->moveToThread(QThread::currentThread());
    //debug
    //_tcpSocket->setEncryKey(ServerSetting::defaultSetting()->getAesKey());

    CNetworkThread::gServerConnected = false;

    bool con = _tcpSocket->connectHostAndVerify(
                     ServerSetting::defaultSetting()->_cloundServerIp,
                     8100,
                     ServerSetting::defaultSetting()->_serial,
                     WEB_ACCEPT) ;

    if(con)
    {
        qDebug() << "--- Peer Connect v2 ---";

        CNetworkThread::gServerConnected = true;

        connect(_tcpSocket,SIGNAL(s_onceData(QString)),this,SLOT(doTcpDataHandle(QString)));
        connect(_tcpSocket,SIGNAL(s_maybeDisconectFromHost()),this,SLOT(doDisconnect()));
        connect(_tcpSocket,SIGNAL(disconnected()),this,SLOT(doDisconnect()));


        if(_project_data.isEmpty()){
           _project_data =  readProjectFile();
        }

        if(!_project_data.isEmpty())
            _cmdParse.projectContext(_project_data);

        //重连后更新工程
        QTimer::singleShot(3000,this,SLOT(doGetProject()));
        //test
        //doGatewayStatusUpdate("@189:300:switch:value:1/6/66:oo");
    }


}

QByteArray CTcpConnect_v2::readProjectFile()
{
    QFile f("project.xml");
    QByteArray d;
    if(f.open(QFile::ReadWrite))
    {
        d = f.readAll();
        f.close();
    }
    else
    {
        qDebug() << "CTcpConnect_v2: readProjectFile fail ";
    }

    return d;
}

void CTcpConnect_v2::writeProjectFile(QByteArray d)
{
    QFile f("project.xml");
    if(f.open(QFile::ReadWrite))
    {
        f.resize(0);
        f.write(d);
        f.close();
    }
    else
    {
        qDebug() << "CTcpConnect_v2: writeProjectFile fail ";
    }
}


void CTcpConnect_v2::doTcpDataHandle(QString d)
{
    QStringList dlist = d.split("#");
    for(int i =0;i<dlist.size();i++)
    {
        QByteArray ret = _cmdParse.anayseJsonData(dlist.at(i).toLocal8Bit());
        qDebug() << "json:" << QString(d);
        if(!ret.isEmpty())
            _tcpSocket->appendSendData(ret);
    }
}

void CTcpConnect_v2::doDisconnect()
{
    // disconnect server success
    qDebug() << "--- Peer DisConnect v2 --- ";
    isSetUpPorject = false;

    CNetworkThread::gServerConnected = false;
}


void CTcpConnect_v2::doStateCheck()
{
     qDebug() << "doStateCheck2:" << " _updateMode = " << _updateMode;

     if(needAddProjectPrefix())
     {
         if(_project_prefix.isEmpty())
         {
             qDebug() << "doStateCheck2: _project_prefix is empty , waiting...";
             doConnectToPushServer();
             return ;
         }
     }

     if(!ServerSetting::defaultSetting()->keyVerifyOK)
     {
         qDebug() << "doStateCheck: serial key not found !" ;
         return ;
     }

    if(_tcpSocket == NULL || (_tcpSocket->state()!=QTcpSocket::ConnectedState &&
       _tcpSocket->state()!=QTcpSocket::ConnectingState) )
    {
        g_connect_fail_times++;
        doConnectToServer();
    }
    else
    {
        if(g_connect_fail_times>0)
            g_connect_fail_times = 0;

        if(!isSetUpPorject)
        {
            int delay = qrand()%3;
            QTimer::singleShot(delay*1000,this,SLOT(doGetProject()));
        }
    }


    if(needAddProjectPrefix())
    {
       if(_pushSocket == NULL ||
               (_pushSocket->state()!=QTcpSocket::ConnectedState && _pushSocket->state()!=QTcpSocket::ConnectingState) )
        {
            doConnectToPushServer();
        }
    }

    qDebug() << "doStateCheck:"<< _tcpSocket->state()  << ", update mode: " << _updateMode ;
    if(_pushSocket!=NULL)
        qDebug() << " _pushSocket:" << _pushSocket->state() ;
}

void CTcpConnect_v2::doConnectToPushServer()
{
    qDebug() <<"Gateway: doConnectToPushServer " << ServerSetting::defaultSetting()->_push_ip << ":" <<
               ServerSetting::defaultSetting()->_push_serial;

    if(ServerSetting::defaultSetting()->_push_ip.length()>12 && ServerSetting::defaultSetting()->_push_serial.length()>1)
    {
        if(_pushSocket != NULL)
        {
            _pushSocket->deleteLater();
            _pushSocket = NULL;
        }

        _pushSocket = new CSyncTcpSocket();
        _pushSocket->moveToThread(QThread::currentThread());

        bool con = _pushSocket->connectHostAndVerify(ServerSetting::defaultSetting()->_push_ip,
                         PORT_PUSH_SERVER,
                         ServerSetting::defaultSetting()->_push_serial,
                         WEB_ACCEPT) ;

        if(con)
        {
            qDebug() << "Gateway: -- Push Connect --";

            connect(_pushSocket,SIGNAL(s_onceData(QString)),
                    this,SLOT(doPushDataHandle(QString)));

            return ;
        }
    }

    qDebug() << "Gateway: -- Push Connect fail --";
}

void CTcpConnect_v2::doPushDataHandle(QString d)
{
    qDebug() << "Gateway Push Socket:" << d;
    QJsonDocument domTree = QJsonDocument::fromJson(d.toLocal8Bit());

    if (domTree.isNull() || domTree.isEmpty())
    {
        qDebug() << "doPushDataHandle Json 格式错误: " << d;
        return ;
    }

    if(domTree.isObject())
    {
        QJsonObject jobj = domTree.object();
        QString cmdStr = "";

        QJsonObject::Iterator it = jobj.begin();
        while (it != jobj.end()) {
            cmdStr = it.key();

            if(it.value().type() == QJsonValue::Object)
            {
                QJsonObject obj = it.value().toObject();

                if(cmdStr == UPDATE_DEV)
                {
                    _project_prefix = obj.value("project_prefix").toString().trimmed();
                    QStringList list = ServerSetting::defaultSetting()->_push_serial.split("_");
                    if(list.size()>1)
                        _device_serial = _project_prefix+list.at(1);
                    else
                        _device_serial = _project_prefix+ServerSetting::defaultSetting()->_push_serial;

                    qDebug() << "Serial: change serial with push serial " << _device_serial;

                    ServerSetting::defaultSetting()->_serial = _device_serial;

                }
                else if(cmdStr == HOTEL_MSG)
                {
                    QString check_type = obj.value("check_type").toString().trimmed();
                    qDebug() << "HOTEL_MSG:" << check_type;

                    //重新获取二维码 http://www.i-ttg.net/hotelManagemen/wxxcx/loginqr?hotelId=4&roomNo=2101
                    emit s_requestQR();

                }

            }

            it++;
        }
    }

}

bool CTcpConnect_v2::needAddProjectPrefix()
{
    if(ServerSetting::defaultSetting()->_push_serial.trimmed().length()>1 &&
            ServerSetting::defaultSetting()->_push_ip.trimmed().length()>1)
    {
        return true;
    }

    return false;
}

void CTcpConnect_v2::doGetProject()
{
    QString reqUrl = "http://www.i-ttg.net/hotelManagemen/wxxcx/grfbs";
    //http://www.i-ttg.net/hotelManagemen/wxxcx/grfbs?serial=

    QString req_serial = _device_serial;
    if(req_serial.isEmpty())
        req_serial = ServerSetting::defaultSetting()->_serial;

    QString req = QString("serial=%1")
            .arg(req_serial);

    qDebug() << "doGetProject:" << reqUrl + "?" + req;

    _http->httpPostSend(reqUrl,req.toUtf8());
}

void CTcpConnect_v2::doReadProjectSetting(QByteArray d)
{
    //qDebug() << "\n\n Project From2: \n" << QString(d);
    if(d == _project_data)
    {
        qDebug() << "\n ## Project From2:  project not change, same with local file !";\
        isSetUpPorject = true;
    }
    else{

        qDebug() << "\n ## Project From2:  project change, reload project !";\

        if(_cmdParse.projectContext(d))
        {
            isSetUpPorject = true;
            _project_data = d;
            writeProjectFile(d);
        }
        else
            qDebug() << "\n Project format error";
    }

}

void CTcpConnect_v2::doChangeUpdateMode(QString mode)
{
    //mode change from none to other, and this is the first time to upload all the device state
    if(MODE_UPDATE_NONE == _updateMode && mode!=MODE_UPDATE_NONE)
    {
       doControlCmd(CMD_CONTROL_READ_ALL);
    }

    if(mode == MODE_UPDATE_ALL || mode == MODE_UPDATE_APP
            ||mode == MODE_UPDATE_NONE || mode == MODE_UPDATE_WEB)
    {
        _updateMode = mode;
    }
    else{
        qDebug() << "!doChangeUpdateMode: fail by unknow mode " << mode;
    }
}

void CTcpConnect_v2::updateDeviceOnline()
{
    QStringList devicesId = _cmdParse._allDeviceId;
    QStringList keys = _allMap.keys();

    for(int i=0;i<keys.size();i++)
    {
        QString k = keys.at(i).split("-").at(0);
        if(!k.isEmpty() && devicesId.indexOf(k) >=0)
        {
            qDebug() << "REAL ALL:" << k;
            devicesId.removeAll(k);
        }
    }

    for(int i=0;i<devicesId.size();i++)
    {
        QString id = devicesId.at(i);
        QString msg = QString("{\"Gate_STATUS\": { \"id\": \"%1\",\"action\": \"online\" },\"Gate_SERIAL\":\"%2\"}")
                .arg(id).arg(ServerSetting::defaultSetting()->_serial);

        _allMap.insert(id,msg);
    }

    QString updateStr = "", updateKeyStr = "";

    for(int i=0;i<keys.size();i++)
    {
        updateStr += "#"+_allMap.value(keys.at(i));
        updateKeyStr += "#"+keys.at(i);
    }

    if(updateStr.length()>0)
    {
        qDebug() << "Gateway all keys: " << keys;
        qDebug() << "Gateway all status: " << updateStr;

        sendDataToServer(updateStr);
    }
}


void CTcpConnect_v2::doControlCmd(QString cmd)
{
    if(cmd == CMD_CONTROL_READ_ALL)
    {
        qDebug() << "CTcpConnect: CMD_CONTROL_READ_ALL";
        //_cmdParse.refreshStatus();
        updateDeviceOnline();
    }
}

void CTcpConnect_v2::doGatewayDeviceStatusUpdate(QString id,QString d)
{
    _updateMap.insert(id,d);
    //控制反馈不能包含在全局里面
    if(!d.contains("Gate_ACK"))
        _allMap.insert(id,d);
}

void CTcpConnect_v2::doUpdateDeviceStatus()
{
    //none mode will retrun ,  the update map will be the same size as all map after a while
//    if(_updateMode == MODE_UPDATE_NONE)
//    {
//        //qDebug() << "_updateMode none , return ";
//        return ;
//    }

    QString updateStr = "#", updateKeyStr = "";
    QList<QString> keys = _updateMap.keys();
    for(int i=0;i<keys.size();i++)
    {
        updateStr += "#"+_updateMap.value(keys.at(i));
        //updateKeyStr += "#"+keys.at(i);
    }
    _updateMap.clear();

    if(updateStr.length()>4)
    {
		qDebug() << "Gateway update keys: " << keys;
        qDebug() << "Gateway update status: " << updateStr;

        sendDataToServer(updateStr);

		//QString allStr = updateKeyStr + "|" +updateStr;

        //_udpUpdate.writeDatagram(allStr.toLocal8Bit(),_hostServer,_hostPort);
    }

    //用户每次登录都会重新刷新设备状态

//    if(_need_update_all)
//    {
//        QString updateStr = "";
//        QList<QString> keys = _allMap.keys();
//        int i = 0 , counter = 0;
//        for(i= _index_all_map;i<keys.size() && counter< g_update_map_size ;i++,counter++,_index_all_map++)
//        {
//            updateStr += "@"+_allMap.value(keys.at(i));
//        }

//        if(i == keys.size())
//        {
//            _need_update_all = false;
//        }

//        // send the status both http and tcp
//        if(updateStr.length()>0)
//        {
//            qDebug() << "\n ####UPDATE: all status "  << updateStr;

//            QString req = QString("%1=%2")
//                    .arg(UPDATE_DEV)
//                    .arg(updateStr);

//            CHttpManger *_upHttp = new CHttpManger();
//            _upHttp->_updateData = updateStr;
//            _upHttp->_try_times ++;

//            connect(_upHttp,SIGNAL(s_reply(QByteArray)),this,SLOT(doGatewayDeviceUpdateResult(QByteArray)));

//            QString reqUrl = ServerSetting::defaultSetting()->_update_url;
//            _upHttp->httpPostSend(reqUrl,req.toUtf8());

//            //tcp send
//            sendDataToServer(req);
//        }
//    }
}

void CTcpConnect_v2::sendDataToServer(QString data)
{
    if (_tcpSocket->state() == QAbstractSocket::ConnectedState)
    {
        _tcpSocket->appendSendData(data);
    }
    else{
        qDebug() << "send tcp data fail by unconnect state: " << data;
    }

}
